This is a race.
Java.lang.ClassLoader is not thread safe when two or more threads try to load the same class simultaneously. It throws a LinkageError exception.
An exception
thrown by this bug:
Exception in thread "Thread-0" java.lang.LinkageError: loader (instance of org/codehaus/groovy/tools/RootLoader):More details about this bug are at GROOVY-3495 JIRA page.
attempted duplicate class definition for name: "groovy/beans/Bindable"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.codehaus.groovy.tools.RootLoader.oldFindClass(RootLoader.java:152)
at org.codehaus.groovy.tools.RootLoader.loadClass(RootLoader.java:124)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.codehaus.groovy.tools.Groovy3495$1.run(Groovy3495.java:34)
The numbers in the following code snippet present the global execution sequence.
org.codehaus.groovy.tools.Rootloader
t1 t2 protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException {
1 3 Class c = this.findLoadedClass(name);
if (c != null) return c;
c = (Class) customClasses.get(name);
2 if (c != null) return c;
try {
5 4 c = oldFindClass(name);
} catch (ClassNotFoundException cnfe) {
// IGNORE
}
...
}
Precondition: thread1 and thread2 both try to load the class "groovy/beans/Bindable"
This bug is reproduced under groovy 1.7.9 and JDK 1.6.0_33.
Execute
the following scripts to run the test to reproduce the bug (assume the
location of the groovy test project is groovy_test_home).
Linux:
${groovy_test_home}/scripts/run3495.sh [--threadnum arg]
Windows:
%groovy_test_home%\scripts\run3495.bat [--threadnum arg]
The default number of threads is 3 if not specified. For example,
${groovy_test_home}/scripts/run3495.sh
is the same as
${groovy_test_home}/scripts/run3495.sh --threadnum 3
| Option | Function | Default Value | Valid Values |
| --threadnum,-tn | number of threads. | 3 | integer |